package com.fulihui.weixinsdk.http;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StreamUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;

import static com.fulihui.weixinsdk.util.LoggerUtils.cutString;

/**
 * Http client 工具类
 *
 * @author test on 2015/4/18.
 * @author leeson update 2017-3-30 09:35:08
 */
public class HttpUtil {
    private static final Logger logger = LoggerFactory.getLogger("HTTPCLIENT_UTIL_LOG");

    /**
     * 获取全Get请求路径
     */
    static String genFullGetUrl(String url, Map<String, String> params, String urlFoot) {
        String paramStr = paramsMapToString(params);
        StringBuilder fullUrl = new StringBuilder(url);
        if (StringUtils.isNotBlank(paramStr)) {
            fullUrl.append("?").append(paramStr);
        }
        if (StringUtils.isNotBlank(urlFoot)) {
            fullUrl.append(urlFoot);
        }
        return fullUrl.toString();
    }

    /**
     * GET请求公共处理部分
     */
    static String executeGet(CloseableHttpClient httpClient, String fullURL) {
        long start = System.currentTimeMillis();
        logger.info("[GET] - {}", fullURL);
        HttpGet httpGet = new HttpGet(fullURL);
        CloseableHttpResponse response = null;
        int status = 0;
        String resp = "-";
        try {
            response = httpClient.execute(httpGet);
            if (response != null && (status = response.getStatusLine().getStatusCode()) == 200) {
                HttpEntity entity = response.getEntity();
                resp = EntityUtils.toString(entity, "utf-8");
                EntityUtils.consume(entity);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            // status, resp, {used}ms
            logger.info("{}, {}, {}ms", new Object[]{status, logger.isDebugEnabled() ? resp : cutString(resp, 50, 20), System.currentTimeMillis() - start});
            if (!httpGet.isAborted()) {
                httpGet.abort();
            }
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
        return resp;
    }

    static String executePost(CloseableHttpClient httpclient, String url, Map<String, String> formParams) throws UnsupportedEncodingException {
        List<NameValuePair> valuePairs = new ArrayList<>();
        if (formParams != null && !formParams.isEmpty()) {
            for (Map.Entry<String, String> entry : formParams.entrySet()) {
                valuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }
        return executePost(httpclient, url, new UrlEncodedFormEntity(valuePairs));
    }

    static String executePost(CloseableHttpClient httpclient, String url, String requestBody) {
        return executePost(httpclient, url, new StringEntity(requestBody, "utf-8"));
    }

    static String executePostFile(CloseableHttpClient httpClient, String url, File file) {
        String resp = null;
        try {
            if (Objects.nonNull(file)) {
                String fileName = file.getName();
                try (FileInputStream fileInputStream = new FileInputStream(file)) {
                    byte[] data = null;

                    try {
                        data = StreamUtils.copyToByteArray(fileInputStream);
                    } catch (IOException var5) {
                        var5.printStackTrace();
                    }

                    HttpEntity reqEntity = MultipartEntityBuilder.create()
                            .addBinaryBody("media", data, ContentType.DEFAULT_BINARY, fileName)
                            .build();

                    resp = executePost(httpClient, url, reqEntity);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return resp;
    }

    /**
     * 执行http post请求
     */
    static String executePost(CloseableHttpClient httpClient, String url, HttpEntity reqEntity) {
        logger.info("[POST] - {}, {}", url, reqEntity);
        long start = System.currentTimeMillis();
        CloseableHttpResponse response = null;
        HttpPost httpPost = null;
        int status = 0;
        String resp = "-";
        try {
            httpPost = new HttpPost(url);
            httpPost.setEntity(reqEntity);
            response = httpClient.execute(httpPost);

            if (response != null && (status = response.getStatusLine().getStatusCode()) == 200) {
                HttpEntity respEntity = response.getEntity();
                resp = EntityUtils.toString(respEntity, "utf-8");
                EntityUtils.consume(respEntity);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            // status, resp, {used}ms
            logger.info("{}, {}, {}ms", new Object[]{status, logger.isDebugEnabled() ? resp : cutString(resp, 50, 20), System.currentTimeMillis() - start});
            if (httpPost != null && !httpPost.isAborted()) {
                httpPost.abort();
            }
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
        return resp;
    }

    /**
     * map转String形式的http url，?k=v&k=v...
     * k按字符串排序
     *
     * @param params map参数
     * @return 请求参数字符串
     */
    static String paramsSortedMapToString(Map<String, String> params) {
        return paramsMapToString(new TreeMap<>(params));
    }

    /**
     * map转String形式的http url，?k=v&k=v...
     *
     * @param params map参数
     * @return 请求参数字符串
     */
    static String paramsMapToString(Map<String, String> params) {
        if (params == null || params.isEmpty()) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (sb.length() > 0) {
                sb.append("&");
            }
            sb.append(entry.getKey()).append("=").append(entry.getValue());
        }
        return sb.toString();
    }

    /**
     * http url字符串参数转map
     *
     * @param params 请求参数字符串 k1=v1&k2=v2&k3=v3
     * @return map集合
     */
    static Map<String, String> paramsStringToMap(String params) {
        String[] kvary = StringUtils.split(params, '&');
        if (kvary == null || kvary.length == 0) {
            return Collections.emptyMap();
        }
        Map<String, String> mapParm = new HashMap<>();
        for (String kv : kvary) {
            if (!StringUtils.contains(kv, '=')) {
                throw new IllegalArgumentException("url params:" + params);
            }
            String[] k_v = StringUtils.split(kv, "=");
            mapParm.put(k_v[0], k_v[1]);
        }
        return mapParm;
    }
}